package com.zyk.scaffold.common.utils.jwt;

import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StopWatch;

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;



public class JwtUtil {

    private static final String JWT_PAYLOAD_KEY = "json";

    private static Date localDateTimeToDate(final LocalDateTime localDateTime) {
        if (null == localDateTime) {
            return null;
        }
        final ZonedDateTime zdt = localDateTime.atZone(ZoneOffset.of("+8"));
        final Date date = Date.from(zdt.toInstant());
        return date;
    }

    /**
     * 公钥解析token
     *
     * @param jwt     jwt
     * @param publicKey 公钥
     * @return Jws<Claims>
     */
    private static Jws<Claims> parserToken(String jwt, PublicKey publicKey) {
        return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(jwt);
    }

    private static String createJTI() {
        return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));
    }

    private static byte[] decryptBASE64(String key) {
        return org.apache.commons.codec.binary.Base64.decodeBase64(key);
    }
    private static final String KEY_ALGORITHM = "RSA";

    public static PrivateKey toPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] decode = Base64.getDecoder().decode(privateKey);
        // 构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(decode);
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 取私钥匙对象
        return keyFactory.generatePrivate(pkcs8KeySpec);
    }

    public static PublicKey toPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 解密由base64编码的公钥
        byte[] decode = Base64.getDecoder().decode(publicKey);
        // 构造X509EncodedKeySpec对象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decode);
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 取公钥匙对象
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 私钥加密token
     *
     * @param json   载荷中的数据
     * @param privateKey 私钥
     * @param expire     过期时间，单位秒
     * @return JWT
     */
    public static String creatJwt(String json, PrivateKey privateKey, long expire) {
        return Jwts.builder()
                .claim(JWT_PAYLOAD_KEY, json)
                .setId(createJTI())
                .setExpiration(localDateTimeToDate(LocalDateTime.now().plusSeconds(expire)))
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();
    }

    /**
     * 获取token中的用户信息
     *
     * @param jwt     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     */
    public static Payload parserJwtPayload(String jwt, PublicKey publicKey) {
        Jws<Claims> claimsJws = parserToken(jwt, publicKey);
        Claims body = claimsJws.getBody();
        Payload payload = new Payload();
        payload.setId(body.getId());
        payload.setJson(body.get(JWT_PAYLOAD_KEY).toString());
        payload.setExpiration(body.getExpiration());
        return payload;
    }
    
    public static void main(String[] args) throws InvalidKeySpecException, NoSuchAlgorithmException {

        String privateKey = "";
        String publicKey = "";
        String qq = "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("1111111111111111111");
        String jwt = creatJwt(qq, toPrivateKey(privateKey), 2L);
        stopWatch.stop();
        Payload payload = parserJwtPayload(jwt, toPublicKey(publicKey));
        for (StopWatch.TaskInfo taskInfo : stopWatch.getTaskInfo()) {
            System.out.println(JSON.toJSONString(taskInfo));
        }
        System.out.println(JSON.toJSONString(payload));
    }

}
